function ForgotPassword(param) {
try{
	var that = this;
	
	var email_check_url = "";
	
	this.j_fp_form = null;
	this.j_fp_email = null;
	this.j_fp_email_error_msg = null;
	this.j_fp_submit = null;
	this.j_fp_submit_status = null;
	
	var email_correct = false;

	var email_existing = false;
	
	var email_validation_locked = true;
	var email_existing_validation_locked = true;
	
	var email_validation_ever_opened = false;
	
	var form_submiting = false;
	
	var email_existing_validating = false;
	var email_existing_validated = false;
	
	var jqxhr_email = null;
	var error_occured = false;
	
	function __construct(p) {
	try{
		for(pkey in p) {
			if(pkey[0] != "_") {
				that[pkey] = p[pkey];
			}
			if(p._email_check_url) {
				email_check_url = p._email_check_url;
			}
		}
		that.j_fp_submit.mousedown(fpSumbitMousedown);
		that.j_fp_form.submit(fpFormSubmit);
		that.j_fp_email.blur(emailInputBlur);
		that.j_fp_email.change(emailInputChange);
		
	}catch(err) {
		alert(err);
	}
	}
		
	function emailInputChange() {
	try{
		if(email_validation_locked) {
			email_validation_locked = false;
		}
		if(email_existing_validation_locked) {
			email_existing_validation_locked = false;
		}
	}catch(err) {
		alert(err);
	}
	}
	
	function emailInputBlur() {
	try{
		if(!form_submiting) {
			validateEmail();
		}
	}catch(err) {
		alert(err);
	}
	}
	
	function validateEmail() {
	try{
		if(!email_validation_locked) {
			email_validation_locked = true;
	    	if(!email_validation_ever_opened) {
	    		email_validation_ever_opened = true;
	    	}
			var email = that.j_fp_email.val();
			var emailLength = jq.trim(email).length;
	
			// check required
			if(!emailLength) {
				email_correct = false;
				that.j_fp_email.data({ 'errorMsg' : "Must not be empty" });
				showWarningMsg(that.j_fp_email, that.j_fp_email_error_msg);
				return false;
			}
			// check regex
			if(email.search(/^[a-zA-Z0-9._-]+@[a-zA-Z0-9.-]+\.[a-zA-Z]{2,4}$/) == -1) {
				email_correct = false;
				that.j_fp_email.data({ 'errorMsg' : "Not a valid email" });
				showWarningMsg(that.j_fp_email, that.j_fp_email_error_msg);
				return false;
			}
			email_correct = true;
			removeWarningMsg(that.j_fp_email, that.j_fp_email_error_msg);
		}else {
			// do nothing
		}
	}catch(err) {
		alert(err);
	}
	}
	
	function validateEmailExisting() {
	try{
		// server side check...
		if(!email_existing_validation_locked) {
			email_existing_validation_locked = true;
			var email = that.j_fp_email.val();
			if(email_existing_validating) {
				jqxhr_email.abort();
			}
			email_existing_validating = true;
			error_occured = false;
			
			jqxhr_email = jq.get(email_check_url, { 'email' : email }, validateEmailSuccess)
	    	.error(function() {
	    		error_occured = true; // block form submission
				var pos_top = that.j_fp_submit.offset().top;
	    		jq.notification({ "pos_top" : pos_top, "width" : 360, "message" : "Oops! An error occurred while processing your request." });
	    	})
	    	.complete(function() {
	   			// complete
				email_existing_validated = true;
		    	email_existing_validating = false;
	    	});
    	}else {
			email_existing_validated = true;
	    	email_existing_validating = false;
		}
	}catch(err) {
		alert(err);
	}
	}

	function validateEmailSuccess(data) {
	try{
		if(data === "TRUE") {
			email_existing = true;
			removeWarningMsg(that.j_fp_email, that.j_fp_email_error_msg);
		}else {
			email_existing = false;
			that.j_fp_email.data({ 'errorMsg' : "Not found" });
			showWarningMsg(that.j_fp_email, that.j_fp_email_error_msg);
		}
	}catch(err) {
		alert(err);
	}
	}
	
	function fpSumbitMousedown(e) {
	try{
		form_submiting = true;

		// reset
		email_existing_validated = false;
		
	}catch(err) {
		alert(err);
	}
	}
	
	function fpFormSubmit(e) {
	try{
    	e.preventDefault();

    	if(!email_validation_ever_opened) {
    		email_validation_ever_opened = true;
			email_validation_locked = false;
    	}
    	
		var fpForm = this;
		validateEmail();
		if(email_correct) {
			that.j_fp_submit_status.css({ "display" : "inline-block" });
			validateEmailExisting();
			isEmailExistingValidated(fpForm);
		}else {
			form_submiting = false;
		}
		
	}catch(err) {
		alert(err);
	}
	}
	
	function isEmailExistingValidated(fpForm) {
	try{
		if(email_existing_validated) {
			form_submiting = false;
			that.j_fp_submit_status.css({ "display" : "none" });
			if(email_existing && !error_occured) {
				fpForm.submit();
				return true;
			}
			return false;
		}else {
			setTimeout( function() {
				isEmailExistingValidated(fpForm);
			}, 300 );
		}
	}catch(err) {
		alert(err);
	}
	}
	
	function showWarningMsg(inputEl, errEl) {
		if (!inputEl.hasClass("error")){
			inputEl.addClass("error");
		}
		errEl.text(inputEl.data("errorMsg"));
		if(!errEl.is(":visible")) {
			errEl.show();
		}
	}
	
	function removeWarningMsg(inputEl, errEl) {
		if(inputEl.hasClass("error")) {
			inputEl.removeClass("error");
		}
		if(errEl.is(":visible")) {
			errEl.hide();
		}
	}
	
	__construct(param);
	
	that.j_fp_email.focus();
	
}catch(err) {
	alert(err);
}
}

	
